Skip to content

DateTime can't be pickled when the container's timezone was set by copying /etc/localtime - #1040

Merged
ashb merged 3 commits into
python-pendulum:masterfrom
juneja-varun:fix-local-timezone-pickling
Oct 10, 2026
Merged

ashb merged 3 commits into
python-pendulum:masterfrom
juneja-varun:fix-local-timezone-pickling

Conversation

@juneja-varun

Copy link
Copy Markdown
Contributor

Fixes #899.

My app runs in a Docker container where the timezone is set the common Alpine/Debian-slim way - cp /usr/share/zoneinfo/Asia/Kolkata /etc/localtime instead of symlinking it. That's a real, correctly-set timezone, but pendulum's get_local_timezone() doesn't recognize a copied file as named (it only reads a name from TZ, /etc/timezone, or a symlink target), so it falls back to reading the raw zoneinfo file directly via Timezone.from_file(). Any pendulum.now() I then try to pickle (I do this passing results back from a multiprocessing.Pool) crashes with _pickle.PicklingError: Cannot pickle a ZoneInfo file from a file stream, because zoneinfo.ZoneInfo.from_file() refuses to pickle anything built that way.

I know switching the Dockerfile to a symlink avoids this entirely, so arguably this is a deployment-config issue rather than a pendulum one. But Timezone.from_file() is already a deliberate, supported fallback here, not an error path - so I think it's worth making that fallback fully correct rather than leaving a trap nobody debugging a PicklingError would think to trace back to how /etc/localtime was set.

Kept the raw TZif bytes around on the instance when built via from_file(), and used them to rebuild an equivalent instance on unpickling instead of inheriting zoneinfo's version, which unconditionally rejects this. Regular Timezone(key) instances still pickle by key as before.

>>> tz = Timezone('Europe/Paris')
"""

_file_bytes: bytes | None = None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is written to, but never used...?

I'm not seeing how this does anything?

@juneja-varun juneja-varun Oct 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the flag and payload __reduce__ needs: if set, it returns _from_pickled_file(data, key) instead of the default, rebuilding the instance from those bytes via from_file() again. Without it, pickling can't reconstruct a file-based instance and crashes - that's the bug this fixes.

Comment thread tests/tz/test_timezone.py
@juneja-varun
juneja-varun requested a review from ashb October 10, 2026 18:29
@codspeed

codspeed Bot commented Oct 10, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 1 benchmark spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

ℹ️ 1 benchmark has no flame graph

The flamegraph could not be generated because we failed to resolve the symbols in the profiling trace. This happens when we fail to harvest information about language frames.

✅ 1 untouched benchmark


Comparing juneja-varun:fix-local-timezone-pickling (5982ec7) with master (b97a3f0)

Open in CodSpeed

@ashb
ashb merged commit 7840d47 into python-pendulum:master Oct 10, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DateTime of version 3.0+ cannot be pickled without timezone

2 participants